package uns.fit.gis.mapdrawer;

import uns.fit.gis.mapobj.Point;

//http://www.longsteve.com/fixmybugs/
public class PolygonClipper {
	//
	// This routine uses the fairly well known Sutherland - Hodgman algorithm for line clipping
	// and expends it (as per Foley & van Dam) for polygons.  It's slower than Liang - Barsky but
	// doesn't produce the redundant vertices at the corners which makes triangle drawing
	// possible.
	//
	// This routine is for the large polys that make up the major ground detail, mainly the
	// islands.
	//

	// Output from the Intersect function
	public static int intersectX;
	public static int intersectY;

	// Constants for the clip boundaries
	public static final int TOP               = 0;
	public static final int LEFT              = 1;
	public static final int BOTTOM            = 2;
	public static final int RIGHT             = 3;

	// clip boundarys
	public static int clip_x_min;
	public static int clip_x_max;
	public static int clip_y_min;
	public static int clip_y_max;

	public static int SutherlandHodgmanPolygonClip(
		int n,
		int [] x, int [] y,	// vertices of input polygon
		int [] u, int [] v,	// vertices of output polygon
		int clipBoundary) {	

		int outCount = 0;

		int sx,sy;
		int px,py;

		int j;

		// start with the last vertex in the in array
		sx = x[n-1];
		sy = y[n-1];

		for(j = 0; j < n; j++) {
			px = x[j];
			py = y[j];

			if(Inside(px, py, clipBoundary)) {
				if(Inside(sx, sy, clipBoundary)) {
					u[outCount] = px;
					v[outCount] = py;
					outCount++;
				} else {
					Intersect(sx,sy,px,py,clipBoundary);
					u[outCount] = intersectX;
					v[outCount] = intersectY;
					outCount++;
					u[outCount] = px;
					v[outCount] = py;
					outCount++;
				}
			} else {
				if(Inside(sx,sy,clipBoundary)) {
					Intersect(sx,sy,px,py,clipBoundary);
					u[outCount] = intersectX;
					v[outCount] = intersectY;
					outCount++;
				}
			}
			sx = px;
			sy = py;
		}

		return outCount;
	}

	public static boolean Inside(int testX, int testY, int clipBoundary) {

		if(clipBoundary == TOP && testY > clip_y_min)
			return true;

		else if(clipBoundary == LEFT && testX > clip_x_min)
			return true;

		else if(clipBoundary == BOTTOM && testY < clip_y_max)
			return true;

		else if(clipBoundary == RIGHT && testX < clip_x_max)
			return true;

		return false;
	}

	public static void Intersect(int x0, int y0, int x1, int y1, int clipBoundary) {

		int xd = x1 - x0;
		int yd = y1 - y0;

		// vertical line condition
		if(xd == 0 || yd == 0) {
			if(clipBoundary == TOP) {
				intersectX = x0;
				intersectY = clip_y_min;
			} else if(clipBoundary == LEFT) {
				// Won't ever happen (line will be entirely inside or outside the edge)
				intersectX = clip_x_min;
				intersectY = y0;
			} else if(clipBoundary == BOTTOM) {
				intersectX = x0;
				intersectY = clip_y_max;
			} else if(clipBoundary == RIGHT) {
                                // Won't ever happen (line will be entirely inside or outside the edge)
				intersectX = clip_x_max;
				intersectY = y0;
			}

			return;
		}

		if(clipBoundary == TOP) {
			intersectX = x0 + (((((xd) * (clip_y_min - y0))<<8) / (yd))>>8);
			intersectY = clip_y_min;
		} else if(clipBoundary == LEFT) {
			intersectX = clip_x_min;
			intersectY = y0 + (((((yd) * (clip_x_min - x0))<<8) / (xd))>>8);
		} else if(clipBoundary == BOTTOM) {
			intersectX = x0 + (((((xd) * (clip_y_max - y0))<<8) / (yd))>>8);
			intersectY = clip_y_max;
		} else if(clipBoundary == RIGHT) {
			intersectX = clip_x_max;
			intersectY = y0 + (((((yd) * (clip_x_max - x0))<<8) / (xd))>>8);
		}
	}
}
